/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as box2d from "./box2d/Box2D/Box2D.js";

let runCount = 7000;
let runCount_thousnd_1 = 100;
let runCount_thousnad_10 = 1000;
let runCount_thousand_100 = 10000;
let runCount_Million_5 = 500000;


function b2AABB_IsValid_Test() {
  let originalAABB = new box2d.b2AABB();
  originalAABB.lowerBound = new box2d.b2Vec2(0, 0);
  originalAABB.upperBound = new box2d.b2Vec2(10, 10);
  let isValid;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    isValid = originalAABB.IsValid();
  }
  const endTime = getDate();
  if (!isValid) {
    throw new Error("jBox2d_b2AABB_IsValid error");
  }
  print(`jBox2d_b2AABB_IsValid: ${endTime - startTime} ms`);
}

function b2AABB_TestOverlap_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(-100, -100);
  aabb.upperBound = new box2d.b2Vec2(100, 100);

  let aabb1 = new box2d.b2AABB();
  aabb1.lowerBound = new box2d.b2Vec2(50, 50);
  aabb1.upperBound = new box2d.b2Vec2(150, 150);
  let result;
  const startTime = getDate();
  for (let i = 0; i < 70000; i++) {
    result = aabb.TestOverlap(aabb1);
  }
  const endTime = getDate();
  if (!result) {
    throw new Error("jBox2d_b2AABB_TestOverlap error");
  }
  print(`jBox2d_b2AABB_TestOverlap: ${endTime - startTime} ms`);
}

function b2World_GetBodyCount_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  def.position.Set(
    box2d.b2RandomRange(-6.0, 0.0),
    box2d.b2RandomRange(4.0, 6.0)
  );
  world.CreateBody(def);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetBodyCount();
  }
  let endTime = getDate();
  if (result != 1) {
    throw new Error("jBox2d_b2World_GetBodyCount error");
  }
  print(`jBox2d_b2World_GetBodyCount: ${endTime - startTime} ms`);
}

function b2World_GetGravity_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let gravity1 = new box2d.b2Vec2(0, -9.9);
  world.m_gravity.Copy(gravity1);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetGravity();
  }
  let endTime = getDate();
  if (result.x != gravity1.x || result.y != gravity1.y) {
    throw new Error("jBox2d_b2World_GetGravity error");
  }
  print(`jBox2d_b2World_GetGravity: ${endTime - startTime} ms`);
}

function b2Body_GetPosition_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.SetTransformVec(new box2d.b2Vec2(2, 5), 0);

  let p;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    p = body.GetPosition();
  }
  let endTime = getDate();
  if (p.x != 2 || p.y != 5) {
    throw new Error("jBox2d_b2Body_GetPosition error");
  }
  print(`jBox2d_b2Body_GetPosition: ${endTime - startTime} ms`);
}

function b2Body_ApplyForceToCenter_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);
  let force = { x: 10, y: 20 };
  let loopCount = 70000;
  const startTime = getDate();
  for (let i = 0; i < loopCount; i++) {
    body.ApplyForceToCenter(force);
  }
  const endTime = getDate();
  if (
    body.m_force.x != loopCount * force.x ||
    body.m_force.y != loopCount * force.y
  ) {
    throw new Error("jBox2d_b2Body_ApplyForceToCenter error");
  }
  print(`jBox2d_b2Body_ApplyForceToCenter: ${endTime - startTime} ms`);
}

function b2Body_SetUserData_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldValue = { x: 1, y: 2 };
  let def = new box2d.b2BodyDef();
  def.userData = oldValue;
  let body = world.CreateBody(def);

  if (
    body.GetUserData().x != oldValue.x ||
    body.GetUserData().y != oldValue.y
  ) {
    throw new Error("jBox2d_b2Body_SetUserData error");
  }

  let newValue = { x: 6, y: 10 };
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetUserData(newValue);
  }
  const endTime = getDate();
  if (
    body.GetUserData().x != newValue.x ||
    body.GetUserData().y != newValue.y
  ) {
    throw new Error("jBox2d_b2Body_SetUserData error");
  }
  print(`jBox2d_b2Body_SetUserData: ${endTime - startTime} ms`);
}

function b2World_GetTreeBalance_Test_01() {
    let gravity = new box2d.b2Vec2(0, -10)
    let world = new box2d.b2World(gravity)

    let treeBalance
    const startTime = getDate()
    for (let i = 0; i < runCount_Million_5; i++) {
      treeBalance = world.GetTreeBalance()
    }
    const endTime = getDate()
    if (treeBalance != 0) {
      throw new Error('jBox2d_b2World_GetTreeBalance(world.m_contactManager.m_broadPhase.m_tree.m_root = null) error')
    }
    print(`jBox2d_b2World_GetTreeBalance(world.m_contactManager.m_broadPhase.m_tree.m_root = null): ${ endTime - startTime } ms`)
}

function b2AABBTest() { // 12个
  b2AABB_IsValid_Test()
  b2AABB_TestOverlap_Test()
}

function b2WorldTest() { // 40个
  b2World_GetBodyCount_Test()
  b2World_GetGravity_Test()
}

function b2BodyTest() { // 70个
  b2Body_GetPosition_Test()
  b2Body_ApplyForceToCenter_Test()
  b2Body_SetUserData_Test()
}

function b2ShapeTest() { // 77个
  b2World_GetTreeBalance_Test_01()
}

function runAllTest() {
  b2AABBTest();
  b2WorldTest();
  b2BodyTest();
  b2ShapeTest();
}

runAllTest();

// function print(str) {
//   console.log(str);
// }

function getDate() {
  return Date.now();
}